package com.jjs.jcenterdemo;

import android.animation.Animator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.graphics.RectF;
import android.graphics.SweepGradient;
import android.graphics.drawable.BitmapDrawable;
import android.os.SystemClock;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.animation.LinearInterpolator;

import com.white.commonlib.widget.AbsView;


/**
 * Created by Administrator on 2017/5/5 0005.
 */

public class RecordButton extends AbsView
{

    private Paint outRingPaint,animRingPaint, ripplePaint, rotatePaint;
    private int normalColor = 0xFF2B8AE4;
    private int pressColor = 0xFF2AA8E3;
    private int rippleColor = 0xFF2ecffc;
    private float outRingStrokeWidth;
    private Bitmap bmpNormal, bmpPress;
    private int[] sweepColors = {0xFFFFFFFF, 0xFF71cbf5, 0xFF2aa8e3};

    public RecordButton(Context context)
    {
        super(context);
        init();
    }

    public RecordButton(Context context, AttributeSet attrs)
    {
        super(context, attrs);
        init();
    }

    public RecordButton(Context context, AttributeSet attrs, int defStyleAttr)
    {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init()
    {
        initPaint();
        initCenterIconBitmap();
    }

    private void initPaint()
    {
        outRingPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        outRingPaint.setStyle(Paint.Style.STROKE);

        animRingPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        animRingPaint.setStyle(Paint.Style.STROKE);

        ripplePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        ripplePaint.setStyle(Paint.Style.STROKE);
        ripplePaint.setColor(rippleColor);

        rotatePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        rotatePaint.setStyle(Paint.Style.STROKE);
    }

    private void initCenterIconBitmap()
    {
        BitmapDrawable bdp = (BitmapDrawable) getContext().getResources().getDrawable(R.drawable.record_button_white);
        bmpNormal = bdp.getBitmap();
    }

    public Bitmap simpleColorMask(Bitmap src, int color)
    {
        Bitmap bmpTarget = src.copy(Bitmap.Config.ARGB_8888, true);
        Canvas canvas = new Canvas(bmpTarget);
        Paint paint = new Paint();
        paint.setFlags(Paint.FILTER_BITMAP_FLAG | Paint.ANTI_ALIAS_FLAG);
        PorterDuffColorFilter filter = new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_ATOP);
        paint.setColorFilter(filter);
        canvas.drawBitmap(bmpTarget, 0, 0, paint);
        return bmpTarget;
    }

    @Override
    public int getDefaultWrapWidth()
    {
        return 100;
    }

    @Override
    public int getDefaultWrapHeight()
    {
        return 100;
    }

    @Override
    protected void onDraw(Canvas canvas)
    {
        if(!isOnLoading)
        {
            drawRing(canvas, isPressed);
            if (isPressed)
            {
                drawRipple(canvas);
            }
            drawAnimRing(canvas);
            drawCenterIcon(canvas, isPressed);
        }else
        {
            drawWaitRing(canvas);
        }
    }

    private void drawWaitRing(Canvas canvas)
    {
        canvas.rotate(angle,centerX, centerY);
        canvas.save();
        canvas.drawArc(rotateRect,0, -345,false, rotatePaint);
        canvas.restore();
    }

    private void drawRing(Canvas canvas, boolean isPress)
    {
        if(isPress)
        {
            outRingPaint.setStyle(Paint.Style.FILL);
            outRingPaint.setColor(pressColor);
        }else
        {
            outRingPaint.setStyle(Paint.Style.STROKE);
            outRingPaint.setStrokeWidth(outRingStrokeWidth);
            outRingPaint.setColor(normalColor);
        }
        canvas.drawCircle(centerX, centerY, (width- outRingStrokeWidth)/2, outRingPaint);
    }

    private void drawRipple(Canvas canvas)
    {
//        canvas.drawArc(mRectRipple, 0, 360, false, ripplePaint);
        canvas.drawCircle(centerX, centerY, mRippleRadius, ripplePaint);
    }

    private void drawCenterIcon(Canvas canvas, boolean isPress)
    {
        if(isPress)
        {
            canvas.drawBitmap(bmpPress, mMatrix, null);
        }else
        {
            canvas.drawBitmap(bmpNormal, mMatrix, null);
        }
    }

    private void drawAnimRing(Canvas canvas)
    {
        if(isPressed)
        {
            animRingPaint.setColor(pressColor);
        }else
        {
            animRingPaint.setColor(normalColor);
        }
        canvas.drawCircle(centerX, centerY, animRingRadius, animRingPaint);
    }

//    public int evaluateColor(float fraction, int startValue, int endValue)
//    {
//        int startInt = (Integer) startValue;
//        int startA = (startInt >> 24) & 0xff;
//        int startR = (startInt >> 16) & 0xff;
//        int startG = (startInt >> 8) & 0xff;
//        int startB = startInt & 0xff;
//
//        int endInt = (Integer) endValue;
//        int endA = (endInt >> 24) & 0xff;
//        int endR = (endInt >> 16) & 0xff;
//        int endG = (endInt >> 8) & 0xff;
//        int endB = endInt & 0xff;
//
//        return (int)((startA + (int)(fraction * (endA - startA))) << 24) |
//                (int)((startR + (int)(fraction * (endR - startR))) << 16) |
//                (int)((startG + (int)(fraction * (endG - startG))) << 8) |
//                (int)((startB + (int)(fraction * (endB - startB))));
//    }

    Matrix mMatrix = new Matrix();

    @Override
    public void onGlobalLayout()
    {
    }

    boolean isPressed;
    boolean isRecording;
    boolean isOnLoading;

    int width, height;
    int gloableWidth, gloableHeight;
    float centerX, centerY;
    ValueAnimator rippleAnim, rotateAnim;
    //收缩扩展圆环的半径，初始值为宽度一半
    private float animRingRadius;
    private float mRippleMaxStrokeWidth;   // 最大波纹半径
    private float mRippleStrokeWidth;
    private boolean isReversed;
    private float mRippleRadius;
    private float mRippleBaseRadius;
    private float angle;
    private RectF rotateRect;

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh)
    {
        super.onSizeChanged(w, h, oldw, oldh);
        gloableWidth = getMeasuredWidth();
        gloableHeight = getMeasuredHeight();
        centerX = gloableWidth/2;
        centerY = gloableHeight/2;

        width = (int) (gloableWidth*0.8f);
        height = (int) (gloableHeight*0.8f);

        outRingStrokeWidth = width / 30.0f;
        animRingRadius = (width- outRingStrokeWidth)/2;

        outRingPaint.setStrokeWidth(outRingStrokeWidth);
        //旋转圆环
        rotatePaint.setStrokeWidth(outRingStrokeWidth);
        SweepGradient sg = new SweepGradient(centerX, centerY, sweepColors, null);
        rotatePaint.setShader(sg);
        rotateRect = new RectF((gloableWidth- width+outRingStrokeWidth)/2, (gloableHeight-height+outRingStrokeWidth)/2,
                (gloableWidth+ width-outRingStrokeWidth)/2, (gloableHeight+height-outRingStrokeWidth)/2);

        animRingPaint.setStrokeWidth(outRingStrokeWidth/3);

        int bwidth = bmpNormal.getWidth();
        float scale = 1.0f;
        float iconWidth = width / 3.0f * 2;
        scale = iconWidth / bwidth * 1.0f;
        mMatrix.setScale(scale, scale);
        mMatrix.postTranslate((gloableWidth - iconWidth)/2, (gloableHeight - iconWidth)/2);

        mRippleMaxStrokeWidth = (gloableWidth - width)/2;
        mRippleBaseRadius = width / 2;
        resetRippleRect();
        initRingAnim();
        initRippleAnim();
        initWaitAnim();
    }

    private void initWaitAnim()
    {
        rotateAnim = ValueAnimator.ofFloat(0, 360);
        rotateAnim.setDuration(1000);
        rotateAnim.setInterpolator(new LinearInterpolator());
        rotateAnim.setRepeatCount(ValueAnimator.INFINITE);
        rotateAnim.setRepeatMode(ValueAnimator.RESTART);
        rotateAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()
        {

            @Override
            public void onAnimationUpdate(ValueAnimator animation)
            {
                angle = (float) animation.getAnimatedValue();
                postInvalidate();
            }
        });
    }

    private void startRippleAnim()
    {
        if(rippleAnim != null)
        {
            rippleAnim.cancel();
            rippleAnim.start();
        }
    }

    public void setOnLoading()
    {
        isOnLoading = true;
        if(rotateAnim != null)
            rotateAnim.start();
    }

    public void reset()
    {
        isPressed = false;
        isRecording = false;

        isOnLoading = false;
        angle = 0;
        if(rotateAnim != null)
            rotateAnim.cancel();
//        if(l != null)
//        {
//            l.onRecordStop();
//        }
        stopRippleAnim();
        resetRippleRect();
    }

//    public void reset()
//    {
//
//    }

    private void stopRippleAnim()
    {
        if(rippleAnim != null)
            rippleAnim.cancel();
    }

    private void resetRippleRect()
    {
        isReversed = false;
        mRippleRadius = mRippleBaseRadius;
    }

    private void initRippleAnim()
    {
        rippleAnim = ValueAnimator.ofFloat(0, mRippleMaxStrokeWidth);
        rippleAnim.setDuration(1200);
        rippleAnim.setInterpolator(new LinearInterpolator());
        rippleAnim.setRepeatCount(ValueAnimator.INFINITE);
        rippleAnim.setRepeatMode(ValueAnimator.REVERSE);
        rippleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()
        {
            @Override
            public void onAnimationUpdate(ValueAnimator animation)
            {
                mRippleStrokeWidth = (float) animation.getAnimatedValue();
                ripplePaint.setStrokeWidth(mRippleStrokeWidth);
                if(!isReversed)
                {
                    mRippleRadius = mRippleBaseRadius + mRippleStrokeWidth / 2;
                }else
                {
                    float delta = mRippleMaxStrokeWidth - mRippleStrokeWidth;
                    mRippleRadius = mRippleBaseRadius + (mRippleMaxStrokeWidth - delta) /2;
                }
                ripplePaint.setColor(pressColor & 0x33FFFFFF);
                postInvalidate();
            }
        });
        rippleAnim.addListener(new Animator.AnimatorListener()
        {
            @Override
            public void onAnimationStart(Animator animation)
            {

            }

            @Override
            public void onAnimationEnd(Animator animation)
            {
            }

            @Override
            public void onAnimationCancel(Animator animation)
            {

            }

            @Override
            public void onAnimationRepeat(Animator animation)
            {
                isReversed = !isReversed;
            }
        });

    }

    private void initRingAnim()
    {
//        ringShrinkAnim = ValueAnimator.ofFloat(animRingRadius, 0);
//        ringShrinkAnim.setDuration(500);
//        ringShrinkAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()
//        {
//            @Override
//            public void onAnimationUpdate(ValueAnimator animation)
//            {
//                animRingRadius = (float) animation.getAnimatedValue();
//                postInvalidate();
//            }
//        });
//
//        ringExpandAnim = ValueAnimator.ofFloat(0, (width- outRingStrokeWidth)/2);
//        ringExpandAnim.setDuration(500);
//        ringExpandAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()
//        {
//            @Override
//            public void onAnimationUpdate(ValueAnimator animation)
//            {
//                animRingRadius = (float) animation.getAnimatedValue();
//                postInvalidate();
//            }
//        });
    }

    long longPressBuffer[] = new long[2];
    boolean isIntercepted;

    private class LongPressThread extends Thread
    {
        @Override
        public void run()
        {
            while (!isIntercepted)
            {
                longPressBuffer[1] = SystemClock.uptimeMillis();
                if (longPressBuffer[1] - longPressBuffer[0] > 200)
                {
                    isIntercepted = true;
                    RecordButton.this.post(new Runnable()
                    {
                        @Override
                        public void run()
                        {
                            isRecording = true;
                            if(l != null)
                            {
                                l.onRecordStart();
                            }
                        }
                    });
                }else
                {
                    SystemClock.sleep(10);
                }
            }
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev)
    {
        switch(ev.getActionMasked())
        {
            case MotionEvent.ACTION_DOWN:

                if(isRecording)
                    return true;

                isIntercepted = false;
                isPressed = true;
                invalidate();

                //长按逻辑
                longPressBuffer[0] = SystemClock.uptimeMillis();
                new LongPressThread().start();

                //呼吸波纹扩散
                startRippleAnim();
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
            case MotionEvent.ACTION_OUTSIDE:

                isIntercepted = true;

                isPressed = false;

                invalidate();

                //圆环扩散
//                ringShrinkAnim.cancel();
//                ringExpandAnim.start();
                //呼吸波纹消失
                stopRippleAnim();
                resetRippleRect();

                if(isRecording)
                {
                    isRecording = false;
                    if(l != null)
                    {
                        l.onRecordStop();
                    }
                }
                break;
            default:
                break;
        }
        return true;
    }

    public boolean isRecordingGoing()
    {
        return isRecording;
    }

    private OnStatuesChangleListener l;

    public void setOnStatuesChangleListener(OnStatuesChangleListener ll)
    {
        this.l = ll;
    }

    public interface OnStatuesChangleListener
    {
        void onRecordStart();
        void onRecordStop();
    }
}
